package com.softfuxi.tbs.app;

import android.content.Context;
import android.util.Base64;
import android.util.Log;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

/**
 *
 *类名称:RSA_EncryptTools.java
 *类描述:加密解密共用类
 *创建人:张小兵
 *创建时间:2015-12-16 上午9:59:24
 *
 **/
public class RSA_EncryptTools {

	/** 指定加密算法为DESede */
	private static String ALGORITHM = "RSA";
	/** 指定公钥存放文件 */
	private static String PUBLIC_KEY_FILE = "public_key.pem";
	/** 指定私钥存放文件 */
	private static String PRIVATE_KEY_FILE = "private_key.pem";
	
	/**
	 * 加密过程
	 * @param "publicKey" 公钥
	 * @param plainTextData 明文数据
	 * @return BASE64编码后的密文
	 * @throws Exception 加密过程中的异常信息
	 */
	public static String encrypt(Context c,String plainTextData) throws Exception {
		// 读取秘钥文件
		String publicKeyString = getFileContent(c,PUBLIC_KEY_FILE);

		String TAG = "### => ";
		Log.e(TAG, "publicKeyString: " + publicKeyString);

		byte[] publicBuffer = Base64.decode(publicKeyString, Base64.DEFAULT);
		Log.e(TAG, "publicBuffer: " + publicBuffer);
		KeyFactory keyFactory = KeyFactory.getInstance("RSA");
		X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicBuffer);
		RSAPublicKey publicKey = (RSAPublicKey) keyFactory.generatePublic(keySpec);
		Log.e(TAG, "publicKey: " + publicKey);

		if (publicKey == null) {
			throw new Exception("加密公钥为空, 请设置");
		}
		Cipher cipher = null;
		try {
			cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
			cipher.init(Cipher.ENCRYPT_MODE, publicKey);
			
			InputStream ins = new ByteArrayInputStream(plainTextData.getBytes());
	        ByteArrayOutputStream writer = new ByteArrayOutputStream();
			
	        //rsa加密的字节大小最多是117，将需要解密的内容，按117位拆开解密
			byte[] buf = new byte[117];
	        int bufl;

	        while ((bufl = ins.read(buf)) != -1) {
	            byte[] block = null;
	            if (buf.length == bufl) {
	                block = buf;
	            } else {
	                block = new byte[bufl];
	                for (int k = 0; k < bufl; k++) {
	                    block[k] = buf[k];
	                }
	            }
	            writer.write(cipher.doFinal(block));
	        }
	        writer.close();
	        
	        // BASE64编码
	        byte[] encryptedData = writer.toByteArray();
			Log.e(TAG, "encryptedData: " + encryptedData);
			return Base64.encodeToString(encryptedData, Base64.DEFAULT);
		} catch (NoSuchAlgorithmException e) {
			throw new Exception("无此加密算法");
		} catch (NoSuchPaddingException e) {
			e.printStackTrace();
			return null;
		} catch (InvalidKeyException e) {
			throw new Exception("加密公钥非法,请检查");
		} catch (IllegalBlockSizeException e) {
			throw new Exception("明文长度非法");
		} catch (BadPaddingException e) {
			throw new Exception("明文数据已损坏");
		}
	}

	/**
	 * 获取秘钥文件内容
	 * @param "keyfileName" 文件名 在assets根目录下
	 * @return 文件内容
	 * @throws IOException
	 * @see
	 */
	public static String getFileContent(Context c,String key) throws IOException {
		InputStream is = c.getResources().getAssets().open(key);
		String keyString = readFile(is);
		return keyString;
	}
	 /**
     * 读取文本文件内容
     * @param "filePath" 文件所在路径
     * @return 文本内容
     * @throws IOException 异常
     * @author cn.outofmemory
     * @date 2013-1-7
     */
    public static String readFile(InputStream is) throws IOException {
        StringBuffer sb = new StringBuffer();
        readToBuffer(sb, is);
        return sb.toString();
    }
    
    /**
     * 将文本文件中的内容读入到buffer中
     * @param buffer buffer
     * @param "filePath" 文件路径
     * @throws IOException 异常
     * @author cn.outofmemory
     * @date 2013-1-7
     */
	private static void readToBuffer(StringBuffer buffer, InputStream is) throws IOException {
        String line; // 用来保存每行读取的内容
        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
        line = reader.readLine(); // 读取第一行
        while (line != null) { // 如果 line 为空说明读完了
            buffer.append(line); // 将读到的内容添加到 buffer 中
            buffer.append("\n"); // 添加换行符
            line = reader.readLine(); // 读取下一行
        }
        reader.close();
        is.close();
    }
	
	/**
	 * 解密过程
	 * @param "privateKey" 私钥
	 * @param cipherData BASE64编码后的密文
	 * @return 明文
	 * @throws Exception 解密过程中的异常信息
	 */
	public static String decrypt(Context c,String cipherData) throws Exception {
		// 读取秘钥文件
		String privateKeyString = getFileContent(c,PRIVATE_KEY_FILE);
		
		byte[] privateBuffer = Base64.decode(privateKeyString,Base64.DEFAULT);
		PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateBuffer);
		KeyFactory keyFactory = KeyFactory.getInstance("RSA");
		RSAPrivateKey privateKey = (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
		
		if (privateKey == null) {
			throw new Exception("解密私钥为空, 请设置");
		}
		try {
			Cipher cipher = Cipher.getInstance("RSA");
			cipher.init(Cipher.DECRYPT_MODE, privateKey);
	        
			// BASE64解码
			byte[] buffer = Base64.decode(cipherData, Base64.DEFAULT);
	        InputStream ins = new ByteArrayInputStream(buffer);
	        ByteArrayOutputStream writer = new ByteArrayOutputStream();
	        
	        //rsa解密的字节大小最多是128，将需要解密的内容，按128位拆开解密
	        byte[] buf = new byte[128];
	        int bufl;

	        while ((bufl = ins.read(buf)) != -1) {
	            byte[] block = null;
	            if (buf.length == bufl) {
	                block = buf;
	            } else {
	                block = new byte[bufl];
	                for (int i = 0; i < bufl; i++) {
	                    block[i] = buf[i];
	                }
	            }
	            writer.write(cipher.doFinal(block));
	        }
	        writer.close();
	        
	        return new String(writer.toByteArray(), "utf-8");
		} catch (NoSuchAlgorithmException e) {
			throw new Exception("无此解密算法");
		} catch (NoSuchPaddingException e) {
			e.printStackTrace();
			return null;
		} catch (InvalidKeyException e) {
			throw new Exception("解密私钥非法,请检查");
		} catch (IllegalBlockSizeException e) {
			throw new Exception("密文长度非法");
		} catch (BadPaddingException e) {
			throw new Exception("密文数据已损坏");
		}
	}
	/**
	 * 加密方法
	 * @param source 源数据
	 * @return
	 * @throws Exception
	 */
	public static String encrypt(String source,Context c) throws Exception {
		/** 将文件中的公钥对象读出 */
		ObjectInputStream ois = new ObjectInputStream(c.getResources().getAssets().open(PUBLIC_KEY_FILE));
		Key key = (Key) ois.readObject();
		ois.close();
		/** 得到Cipher对象来实现对源数据的RSA加密 */
		Cipher cipher = Cipher.getInstance(ALGORITHM);
		cipher.init(Cipher.ENCRYPT_MODE, key);
		byte[] b = source.getBytes();
		/** 执行加密操作 */
		byte[] b1 = cipher.doFinal(b);
		return Base64.encodeToString(b1, Base64.DEFAULT);
	}
	
	/**
	 * 解密方法
	 * @param cryptograph
	 * @return
	 * @throws Exception
	 */
	public static String decrypt(String cryptograph,Context c) throws Exception {
		/** 将文件中的私钥对象读出 */
		ObjectInputStream ois = new ObjectInputStream(c.getResources().getAssets().open(PRIVATE_KEY_FILE));
		Key key = (Key) ois.readObject();
		/** 得到Cipher对象对已用公钥加密的数据进行RSA解密 */
		Cipher cipher = Cipher.getInstance(ALGORITHM);
		cipher.init(Cipher.DECRYPT_MODE, key);
		byte[] b1=Base64.decode(cryptograph, Base64.DEFAULT);
		
		/** 执行解密操作 */
		byte[] b = cipher.doFinal(b1);
		return new String(b);
	}

}
